建立一個.Net Core Web Api的專案,取名API Gateway
在Models目錄底下簡單建一個用來標示服務的class 只包含服務名字跟位置
namespace APIGateway.Models
{
    public class MicroService
    {
        public string Name { get; set; }
        public string Location { get; set; }
    }
}
加入一個使用web api用以接受Service註冊跟註銷的Controller
using APIGateway.Models; //記得引入Models
namespace APIGateway.Controllers
{
    [Produces("application/json")]
    [Route("api/ServiceRegistry")]
    public class ServiceRegistryController : Controller
    {
        static List<MicroService> serviceList = new List<MicroService>() {
            new MicroService() { Name="API Gateway", Location="http://localhost:2324" }
        };
        // GET: api/ServiceRegistry
        [HttpGet]
        public IEnumerable<MicroService> Get()
        {
            return serviceList;
        }
        // POST: api/ServiceRegistry
        [HttpPost]
        public void Post([FromBody]MicroService service)
        {
            serviceList.Add(service);
        }
        // DELETE: api/ServiceRegistry/{serviceName}
        [HttpDelete("{serviceName}")]
        public void Delete(string serviceName)
        {
            serviceList.Remove(serviceList.First(s => s.Name == serviceName));
        }
    }
}
再建立一個.Net Core Web Api的專案, 取名ProductService
接著為了要在Service的啟動跟停止發request給ServiceRegistryController註冊跟註銷服務
需要在StartUp.cs寫一些code,
在Configure方法加入參數IApplicationLifetime appLifetime,接著利用appLifeTime掛載host啟動跟停止時要實施的方法:
appLifetime.ApplicationStarted.Register(OnStarted);
appLifetime.ApplicationStopped.Register(OnStopped);
在OnStarted跟OnStopped分別發送request給ServiceRegistry在開始時註冊服務,取消時註銷服務
另外因為找不到如何手動關閉 ProductService我又加了一段code讓他自己關閉(利用applifetime.StopApplication())
app.Use(next =>
{
return async (context) =>
{
await context.Response.WriteAsync("Application will shut down");
await Task.Delay(10000);
appLifetime.StopApplication();
};
});
   public class Startup
    {
        IServerAddressesFeature serverAddressesFeature;
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public IConfiguration Configuration { get; }
        // This method gets called by the runtime. 
        Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }
        // This method gets called by the runtime. 
        Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, 
                              IHostingEnvironment env, 
                              IApplicationLifetime appLifetime)
        {
            //serverAddressesFeature = app.ServerFeatures.Get<IServerAddressesFeature>(); 
            //Get Kestrel Uri 
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseMvc();
            appLifetime.ApplicationStarted.Register(OnStarted);
            appLifetime.ApplicationStopped.Register(OnStopped);
            app.Use(next =>
            {
                return async (context) =>
                {
                    await context.Response.WriteAsync("Application will shut down");
                    await Task.Delay(10000);
                    appLifetime.StopApplication();
                };
            });
        }
        private void OnStarted() {
            Console.WriteLine("Starting");
            using (HttpClient client = new HttpClient()) {
                //string data = serverAddressesFeature.Addresses.FirstOrDefault().ToString(); //Kestrel
                string IISExpressIP = "http://localhost:4147";
                string json = JsonConvert.SerializeObject(new{ Name="ProductService",
                Location=IISExpressIP });
                HttpContent contentPost = new StringContent(json, Encoding.UTF8,
                "application/json");
                HttpResponseMessage response =
                client.PostAsync("http://localhost:2343//api/ServiceRegistry",
                contentPost).Result;                
            }
        }
        private void OnStopped() {
            using (HttpClient client = new HttpClient()) {
                string Uri = "http://localhost:2343/api/ServiceRegistry";
                string IISExpressIP = "http://localhost:4147";
                var service = new { Name = "ProductService", Location = IISExpressIP };
                string json = JsonConvert.SerializeObject(service);
                HttpContent contentPost = new StringContent(json, 
                Encoding.UTF8, "application/json");
                string requestUri = $"{Uri}/{service.Name}";
                HttpResponseMessage response = client.DeleteAsync(requestUri).Result;
            }
            Console.WriteLine("Stopped");
        }
    }
    ```
利用ctrl-F5啟動API Gateway專案,
在ProductService中設置中斷點在private void OnStopped() 
利用F5啟動ProductService,
停在中斷點時利用Postman發送get給http://localhost:2343/api/Registry
會看到ProductService已經被註冊
[
    {
    "name": "Initial",
    "location": "http://localhost:2324"
    },
    {
    "name": "ProductService",
    "location": "http://localhost:4147"
    }
]
F5繼續,直到程式中止,利用Postman發送get給http://localhost:2343/api/Registry
會看到ProductService已經被註銷
[
    {
    "name": "Initial",
    "location": "http://localhost:2324"
    }
]
# 這邊重點是我們可以利用appLifetime來處理服務的啟動或是結束事件。
這個簡單的Service Registry只是練習.Net Core下的產物, 實際上的例子多半會用第三方的套件像是ZooKeeper、Netflix Eureka來實現Service registry
另外有一個有問題的地方是,本來嘗試要自動取得ProductService的Uri,但發現只能取得Kestrel的Uri,
而無法取得最終IIS Express的Uri,所以只好先hard code了, 之後找到解法再來修正
Merry Christmas!
 版主你好 因為我是用.net core 6實作 想詢問關於productService啟動時 會出現以下錯誤
請問是否是因為我Url設定錯誤導致的呢?
請問版主的 HttpResponseMessage response = client.PostAsync("http://localhost:2343//api/ServiceRegistry",contentPost).Result;
的Url 是對照 專案api gateway ip Url嗎?
另外請問 ProductService 這個專案controller有新增RegistryController.cs嗎?